package com.yanggu.spock.service

import com.yanggu.spock.dao.MoneyDao
import com.yanggu.spock.dao.UserDao
import com.yanggu.spock.domain.entity.UserEntity
import com.yanggu.spock.domain.vo.OrderVO
import com.yanggu.spock.domain.vo.UserVO
import com.yanggu.spock.exception.APIException
import spock.lang.Specification
import spock.lang.Unroll

class UserServiceTest extends Specification {

    def userService = new UserService()

    def userDao = Mock(UserDao.class)

    def moneyDao = Mock(MoneyDao.class)

    void setup() {
        userService.setUserDao(userDao)
        userService.setMoneyDao(moneyDao)
    }

    def "test getUserById"() {
        given: "请求参数设置"
        def user1 = new UserEntity(id: 1, name: "张三", province: "上海")
        def user2 = new UserEntity(id: 2, name: "李四", province: "江苏")

        and: "mock掉接口返回的用户信息"
        userDao.getUserInfo() >> [user1, user2]

        when: "调用获取用户信息方法"
        def response = userService.getUserById(1)

        then: "验证返回结果是否符合预期值"
        //会对变量response进行解构，将成员变量的值复制给对应的变量
        //变量都是定义在左边。期望值都定义在右边
        with(response) {
            name == "张三"
            abbreviation == "沪"
            postCode == 200000
        }
    }

    /**
     * where表格测试
     */
    @Unroll
    def "当输入的用户id为: #id, 省份: #province, 手机号码: #paramTelephone时, 返回的邮编是: #postCodeResult，处理后的电话号码是: #telephoneResult"() {
        given: "mock掉接口返回的用户信息"
        userDao.getUserInfo() >> mockUserList(id, province, paramTelephone)

        when: "调用获取用户信息方法"
        def response = userService.getUserById(id)

        then: "验证返回结果是否符合预期值"
        with(response) {
            postCode == postCodeResult
            telephone == telephoneResult
        }

        where: "表格方式验证用户信息的分支场景"
        id | province | paramTelephone || postCodeResult | telephoneResult
        1  | "上海"   | "13866667777"  || 200000         | "138****7777"
        2  | "北京"   | "13811112222"  || 100000         | "138****2222"
        3  | "南京"   | "13833334444"  || null           | "138****4444"
    }

    /**
     * 异常测试
     */
    @Unroll
    def "验证用户信息的合法性: #expectedMessage"() {
        when: "调用校验用户方法"
        userService.validateUser(user)

        then: "捕获异常并设置需要验证的异常值"
        def exception = thrown(expectedException)
        with(exception) {
            errorCode == expectedErrCode
            errorMessage == expectedMessage
        }

        where: "表格方式验证用户信息的合法性"
        user           || expectedException | expectedErrCode | expectedMessage
        getUser(10001) || APIException      | "10001"         | "user is null"
        getUser(10002) || APIException      | "10002"         | "user name is null"
        getUser(10003) || APIException      | "10003"         | "user age is null"
        getUser(10004) || APIException      | "10004"         | "user telephone is null"
        getUser(10005) || APIException      | "10005"         | "user sex is null"
        getUser(10006) || APIException      | "10006"         | "user order is null"
        getUser(10007) || APIException      | "10007"         | "order number is null"
        getUser(10008) || APIException      | "10008"         | "order amount is null"
    }

    def "测试void方法"() {
        given: "设置请求参数"
        def userVO = new UserVO(name: "James", country: "美国")
        userVO.userOrders = [new OrderVO(orderNum: "1", amount: 10000), new OrderVO(orderNum: "2", amount: 1000)]

        when: "调用设置订单金额的方法"
        userService.setOrderAmountByExchange(userVO)

        then: "验证调用获取最新汇率接口的行为是否符合预期: 一共调用2次, 第一次输出的汇率是0.1413, 第二次是0.1421"
        2 * moneyDao.getExchangeByCountry(_) >> 0.1413 >> 0.1421

        and: "验证根据汇率计算后的金额结果是否正确"
        with(userVO) {
            userOrders[0].amount == 1413
            userOrders[1].amount == 142.1
        }
    }

    def mockUserList(Integer id, String province, String telephone) {
        return [new UserEntity(id: id, province: province, telephone: telephone)]
    }

    def getUser(errCode) {
        def user = new UserVO()
        def condition1 = {
            user.name = "杜兰特"
        }
        def condition2 = {
            user.age = 20
        }
        def condition3 = {
            user.telephone = "15801833812"
        }
        def condition4 = {
            user.sex = "男"
        }
        def condition5 = {
            user.userOrders = [new OrderVO()]
        }
        def condition6 = {
            user.userOrders = [new OrderVO(orderNum: "123456")]
        }

        switch (errCode) {
            case 10001:
                user = null
                break
            case 10002:
                user = new UserVO()
                break
            case 10003:
                condition1()
                break
            case 10004:
                condition1()
                condition2()
                break
            case 10005:
                condition1()
                condition2()
                condition3()
                break
            case 10006:
                condition1()
                condition2()
                condition3()
                condition4()
                break
            case 10007:
                condition1()
                condition2()
                condition3()
                condition4()
                condition5()
                break
            case 10008:
                condition1()
                condition2()
                condition3()
                condition4()
                condition5()
                condition6()
                break
        }
        return user
    }

}
